/*
 * Copyright (c) MuleSoft, Inc.  All rights reserved.  http://www.mulesoft.com
 * The software in this package is published under the terms of the CPAL v1.0
 * license, a copy of which has been included with this distribution in the
 * LICENSE.txt file.
 */
package org.mule.extension.db.internal.domain.executor;

import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.CoreMatchers.sameInstance;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.fail;
import static org.mockito.Answers.RETURNS_DEEP_STUBS;
import static org.mockito.Matchers.any;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import org.mule.extension.db.internal.domain.autogeneratedkey.AutoGenerateKeysStrategy;
import org.mule.extension.db.internal.domain.connection.DbConnection;
import org.mule.extension.db.internal.domain.query.Query;
import org.mule.extension.db.internal.domain.query.QueryTemplate;
import org.mule.extension.db.internal.domain.statement.StatementFactory;
import org.mule.tck.junit4.AbstractMuleTestCase;
import org.mule.tck.size.SmallTest;

import java.sql.SQLException;
import java.sql.Statement;

import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.runners.MockitoJUnitRunner;

@SmallTest
@RunWith(MockitoJUnitRunner.class)
public class AbstractSingleQueryExecutorTestCase extends AbstractMuleTestCase {

  @Mock
  private StatementFactory statementFactory;

  @Mock
  private Statement statement;

  @Mock
  private AutoGenerateKeysStrategy autoGenerateKeysStrategy;

  @Mock(answer = RETURNS_DEEP_STUBS)
  private Query query;

  @Mock
  private DbConnection dbConnection;

  @Mock
  private SQLException sqlException;

  private AbstractSingleQueryExecutor executor;

  @Before
  public void before() throws Exception {
    when(statementFactory.create(any(DbConnection.class), any(QueryTemplate.class), any(AutoGenerateKeysStrategy.class)))
        .thenReturn(statement);
    when(statementFactory.create(any(DbConnection.class), any(QueryTemplate.class))).thenReturn(statement);

    executor = new AbstractSingleQueryExecutor(statementFactory) {

      @Override
      protected Object doExecuteQuery(DbConnection connection, Statement statement, Query query) throws SQLException {
        throw sqlException;
      }

      @Override
      protected Object doExecuteQuery(DbConnection dbConnection, Statement statement, Query query,
                                      AutoGenerateKeysStrategy autoGenerateKeysStrategy)
          throws SQLException {
        throw sqlException;
      }
    };
  }

  @Test
  public void statementClosedWhenFailedUsingKeyGeneration() throws Exception {
    try {
      executor.execute(dbConnection, query, autoGenerateKeysStrategy);
      fail("Was expecting a failure");
    } catch (SQLException e) {
      assertExpectedException(e);
      assertStatementClosed();
    }
  }

  @Test
  public void statementClosedWhenFailedWithoutKeyGeneration() throws Exception {
    try {
      executor.execute(dbConnection, query);
      fail("Was expecting a failure");
    } catch (SQLException e) {
      assertExpectedException(e);
      assertStatementClosed();
    }
  }

  private void assertStatementClosed() throws SQLException {
    verify(statement).close();
  }

  private void assertExpectedException(SQLException e) {
    assertThat(e, is(sameInstance(sqlException)));
  }
}
